#region Apache License
//
// Licensed to the Apache Software Foundation (ASF) under one or more 
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership. 
// The ASF licenses this file to you under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with 
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#endregion



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

using IPSim.Util;
using IPSim.GUI.Devices;

namespace IPSim.GUI
{
    public partial class NetworkDesigner : UserControl
    {
        #region Members

        private NetworkDesign networkDesign = new NetworkDesign();
        private BaseDevice clickedDevice;

        private bool isMoving = false;
        private IMoveController moveController;
        private IController controller;

        // Link managment temporary members
        private bool isCreatingLink = false;
        private ConnectorDevice startConnector;
        private ConnectorDevice endConnector;
        private BaseLinkDevice link;



        #endregion

        #region Methods

        public Point Gsc2Goc(Point gsp)
        {
            gsp.X = gsp.X - this.AutoScrollPosition.X;
            gsp.Y = gsp.Y - this.AutoScrollPosition.Y;
            return gsp;
        }
        
        public NetworkDesigner()
        {
            InitializeComponent();

            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);

            networkDesign.PropertyChanged += new EventHandler(design_PropertyChanged);
            networkDesign.AppearancePropertyChanged += new EventHandler(design_AppearancePropertyChanged);
            networkDesign.DevicePropertyChanged += new EventHandler(design_DevicePropertyChanged);
            networkDesign.WindowSize = this.Size;                                    
        }

        private void StartLinkCreation(ConnectorDevice starter, Point mousePos)
        {
            if (!starter.IsConnected)
            {
                isCreatingLink = true;
                startConnector = starter;
                endConnector = new ConnectorDevice(starter.ParentDevice);
                endConnector.Location = startConnector.Location;
                IMoveController controller = (IMoveController)((IControllable)endConnector).GetController();
                controller.Start(mousePos);
                link = new StraightLinkDevice(startConnector, endConnector);
            }
        }

        private void EndLinkCreation()
        {
            if (link.Connector2 != endConnector)
            {
                networkDesign.CreateLink(link.Connector1, link.Connector2);
            }

            link.Connector1.DisconnectLink(link);
            isCreatingLink = false;
            startConnector = null;
            endConnector = null;
            link = null;
            this.Invalidate();
        }

        #endregion

        #region Properties

        public NetworkDesign NetworkDesign
        {
            get { return networkDesign; }
        }

        #endregion

        #region Events

        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            Graphics g = e.Graphics;

            this.AutoScrollMinSize = new Size(networkDesign.Location.X + networkDesign.Size.Width, networkDesign.Location.Y + networkDesign.Size.Height);

            Point scrollPoint = this.AutoScrollPosition;
            g.TranslateTransform(scrollPoint.X, scrollPoint.Y);

            g.SmoothingMode = networkDesign.SmoothingMode;
            g.PixelOffsetMode = networkDesign.PixelOffsetMode;
            g.CompositingQuality = networkDesign.CompositingQuality;
            
            networkDesign.DrawGrid(g, e.ClipRectangle);
            networkDesign.DrawElements(g, e.ClipRectangle);
            networkDesign.DrawSelections(g, e.ClipRectangle);
            if (isCreatingLink)
            {
                link.Draw(g);
            }
            base.OnPaint(e);

        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            networkDesign.WindowSize = this.Size;
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            Point mousePoint = Gsc2Goc(new Point(e.X, e.Y));

            switch (networkDesign.Action)
            {
                case DesignerAction.Select:
                    if (e.Button == MouseButtons.Left)
                    {
                        clickedDevice = networkDesign.FindDevice(mousePoint);
                        networkDesign.ClearSelection();

                        if (clickedDevice != null)
                        {                            
                            networkDesign.ClearSelection();
                            networkDesign.SelectDevice(clickedDevice);
                            if (clickedDevice is ConnectorDevice)
                                clickedDevice = ((ConnectorDevice)clickedDevice).ParentDevice;
                            if (clickedDevice is IControllable)
                            {
                                controller = ((IControllable)clickedDevice).GetController();
                                if (controller is IMoveController)
                                {
                                    isMoving = true;
                                    moveController = (IMoveController)controller;
                                    moveController.Start(new Point(e.X, e.Y));
                                }
                            }
                        }
                        this.Invalidate();
                    }
                    break;
                case DesignerAction.Connect:
                    if (e.Button == MouseButtons.Left)
                    {
                        clickedDevice = networkDesign.FindDevice(mousePoint);
                        if (clickedDevice is ConnectorDevice)
                        {
                            Logger.log("LINK_MOUSE_DOWN");
                            StartLinkCreation((ConnectorDevice)clickedDevice, clickedDevice.Location);
                            clickedDevice = null;
                        }
                    }
                    break;
                // ADD
                case DesignerAction.Add:

                    if (e.Button == MouseButtons.Left)
                    {
                        mousePoint = new Point(e.X, e.Y);
                        BaseDevice device;
                        switch (networkDesign.DeviceType)
                        {
                            case DeviceType.Rectangle:
                                device = new RectangleDevice(e.X-25,e.Y-25,50,50);
                                break;
                            case DeviceType.Computer:
                                device = new ComputerDevice(e.X - 32, e.Y - 32);
                                break;
                            case DeviceType.Hub:
                                device = new HubDevice(e.X - 32, e.Y - 32);
                                break;
                            case DeviceType.Switch:
                                device = new SwitchDevice(e.X - 32, e.Y - 32);
                                break;
                            case DeviceType.Router:
                                device = new RouterDevice(e.X - 32, e.Y - 32);
                                break;
                            default:
                                device = new RectangleDevice(e.X - 25, e.Y - 25, 50, 50);
                                break;
                        }
                        networkDesign.AddDevice(device);
                    }
                    break;

                case DesignerAction.Delete:
                    if (e.Button == MouseButtons.Left)
                    {
                        networkDesign.DeleteDevice(new Point(e.X, e.Y));
                        networkDesign.Action = DesignerAction.Select;
                        networkDesign.ClearSelection();
                    }
                    break;
            }

            base.OnMouseDown(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                Point dragPoint = new Point(e.X, e.Y);
                if (isMoving)
                {
                    if (moveController != null)
                            moveController.Move(dragPoint);
                }
                if (isCreatingLink)
                {
                    clickedDevice = networkDesign.FindDevice(dragPoint);
                    if ((clickedDevice is ConnectorDevice) && networkDesign.CanCreateLink(startConnector, (ConnectorDevice)clickedDevice))
                        link.Connector2 = (ConnectorDevice) clickedDevice;
                    else
                        link.Connector2 = endConnector;

                    IMoveController ctrl = (IMoveController)((IControllable)endConnector).GetController();
                    ctrl.Move(dragPoint);
                    this.Invalidate();
                }
            }
            base.OnMouseMove(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (isMoving)
            {
                isMoving = false;
                if (moveController != null)
                    moveController.End();
            }
            if (isCreatingLink)
            {
                EndLinkCreation();
            }
            networkDesign.CalcWindow();
            this.Invalidate();
            base.OnMouseUp(e);
        }

        private void design_PropertyChanged(object sender, EventArgs e)
        {
            this.Invalidate();
        }

        private void design_AppearancePropertyChanged(object sender, EventArgs e)
        {
            this.Invalidate();
        }

        private void design_DevicePropertyChanged(object sender, EventArgs e)
        {
            this.Invalidate();
        }

        #endregion
    }


    #region Enums

    public enum DesignerAction
    {
        Select,
        Delete,
        Connect,
        Add
    }

    public enum DeviceType
    {
        Rectangle,
        Computer,
        Router,
        Switch,
        Hub
    }

    public enum LineType
    {
        Straight
    }

    #endregion
}
